
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package almacenamiento.Tarea_Gestion_Paginas_Ranuras;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import almacenamiento.*;

/**
 *
 * @author SaHa
 */
public class PaginaRanuras implements Iterable<Tupla>
{    
    //-------------------- Atributos ----------------------------
    
    /** El ID de la página. */
    private IdentificadorPagina IdPagina;
    /** El numero de elementos del registro de la cabecera. */
    private int NumeroRegistrosCabecera;
    /** Final del espacio vacio del bloque. */
    private int FinEspacioVacio;
    /** Array que contiene la ubicacion y el tamaño de los registros(tuplas). */
    private List<Par> ArrayUbicacionTamaño; //(ubicacion,tamaño)->(4096,6)
    /** Las tuplas de la página. */
    private List<Tupla> Tuplas;    
    /** El esquema de la relación al que pertenece la página. */
    private Relacion Relacion;
    /** El espacio libre en la página. */
    private int EspacioVacio;
    /** Espacio que ocupa en la pagina toda la cabecera. */
    private int FinCabecera;

    //-------------------- Constructores ----------------------------
    
    /**
     * Crear una nueva página dado el esquema de la relación y el IdPagina.
     * 
     * @param relacion la relación al que pertenece la página.
     * @param idPagina el ID de la página.
     */
    
    public PaginaRanuras(Relacion Relacion, IdentificadorPagina IdPagina) 
    {
        this.NumeroRegistrosCabecera=0;
        this.FinCabecera=8;
        this.FinEspacioVacio=4096;
        this.Relacion = Relacion;
        this.IdPagina = IdPagina;
        this.ArrayUbicacionTamaño=new ArrayList<Par>();
        this.Tuplas = new ArrayList<Tupla>();
        // tamaño de página 4k
        EspacioVacio = 4096 - (2*Convert.INT_SIZE);
    }
    
    //-------------------- Propiedades ----------------------------

    public List<Par> getArrayUbicacionTamaño() {
        return ArrayUbicacionTamaño;
    }

    public void setArrayUbicacionTamaño(List<Par> ArrayUbicacionTamaño) {
        this.ArrayUbicacionTamaño = ArrayUbicacionTamaño;
    }

    public int getEspacioVacio() {
        return EspacioVacio;
    }

    public void setEspacioVacio(int EspacioVacio) {
        this.EspacioVacio = EspacioVacio;
    }

    public int getFinCabecera() {
        return FinCabecera;
    }

    public void setFinCabecera(int FinCabecera) {
        this.FinCabecera = FinCabecera;
    }

    public int getFinEspacioVacio() {
        return FinEspacioVacio;
    }

    public void setFinEspacioVacio(int FinEspacioVacio) {
        this.FinEspacioVacio = FinEspacioVacio;
    }

    public IdentificadorPagina getIdPagina() {
        return IdPagina;
    }

    public void setIdPagina(IdentificadorPagina IdPagina) {
        this.IdPagina = IdPagina;
    }

    public int getNumeroRegistrosCabecera() {
        return NumeroRegistrosCabecera;
    }

    public void setNumeroRegistrosCabecera(int NumeroRegistrosCabecera) {
        this.NumeroRegistrosCabecera = NumeroRegistrosCabecera;
    }

    public Relacion getRelacion() {
        return Relacion;
    }

    public void setRelacion(Relacion Relacion) {
        this.Relacion = Relacion;
    }

    public List<Tupla> getTuplas() {
        return Tuplas;
    }

    public void setTuplas(List<Tupla> Tuplas) {
        this.Tuplas = Tuplas;
    }
    
    //-------------------- Metodos ----------------------------
    
    /**
     * Verificar si la página tiene espacio para mas tuplas.
     *
     * @return <pre>true</pre> si hay espacio para mas tuplas
     * en la página, <pre>false</pre> en caso contrario.
     */
    public boolean hayEspacio(Tupla t) 
    {
        return EspacioVacio >= (GestorIOTupla.byteSize(getRelacion(), t)+8);
    }

    /**
     * Devolver el número de tuplas almacendas en la página.
     *
     * @return numero de tuplas almacenadas en la página.
     */
    public int getNumeroDeTuplas() 
    {
        return Tuplas.size();
    }

    /**
     * Almacenar una nueva tupla en la página.
     * 
     * @param tupla la nueva tupla.
     * @throws ArrayIndexOutOfBoundsException lanzar si el límite del tamaño de la
     * página no es suficiente para almacenar la tupla.
     */
    public void adicionarTupla(Tupla tupla) throws ArrayIndexOutOfBoundsException 
    {
        if (hayEspacio(tupla)) 
        {
            int tamañotupla = GestorIOTupla.byteSize(getRelacion(), tupla);            
            Par<Integer,Integer> par = new Par(FinEspacioVacio-tamañotupla,tamañotupla);
            ArrayUbicacionTamaño.add(par);
            FinCabecera=FinCabecera+8;
            Tuplas.add(tupla);
            FinEspacioVacio=FinEspacioVacio-tamañotupla;
            EspacioVacio = FinEspacioVacio-FinCabecera;
            NumeroRegistrosCabecera++;
        } 
        else 
        {
            throw new ArrayIndexOutOfBoundsException("No hay espacio en la página.");
        }
    }

    /**
     * Cambiar una tupla.
     * 
     * @param indice el indice de la tupla a ser cambiada.
     * @param tupla la nueva tupla.
     * @throws ArrayIndexOutOfBoundsException lanzar si el límite del tamaño de la
     * página no es suficiente para almacenar la nueva tupla.
     */
    public void setTupla(int index, Tupla tupla) throws ArrayIndexOutOfBoundsException 
    {
        if (!puedeCambiar(index, tupla)) 
        {
            throw new ArrayIndexOutOfBoundsException("No hay espacio en la página.");
        }
        Tuplas.set(index, tupla);
    }

    /**
     * Verificar si un especifico indice de una tupla puede ser reemplazado 
     * por una nueva tupla.
     *
     * @param index indice de la tupla a ser reemplado.
     * @param nt la nueva tupla.
     */
    public boolean puedeCambiar(int index, Tupla nt) 
    {
        return (EspacioVacio
                + GestorIOTupla.byteSize(getRelacion(), Tuplas.get(index))
                - GestorIOTupla.byteSize(getRelacion(), nt)) >= 0;
    }

    /**
     * Intercambiar dos tuplas en base a sus indices.
     *
     * @param x el indice de la primera tupla.
     * @param y el índice de la segunda tupla.
     */
    public void intercambiar(int x, int y) 
    {
        Tupla t = Tuplas.get(x);
        Tuplas.set(x, Tuplas.get(y));
        Tuplas.set(y, t);
    }

    /**
     * Recuperar una determinada tupla de la página.
     * 
     * @param index el indice de la tupla a ser recuperada.
     * @return una tupla en la posición de index.
     */
    public Tupla recuperarTupla(int index) 
    {
        return Tuplas.get(index);
    }

    /**
     * Recuperar el ID de la pagina
     * 
     * @return ID de la página
     */
    public IdentificadorPagina getIdentificadorPagina() 
    {
        return IdPagina;
    }

    /**
     * Devolver un iterator de tuplas de la página.
     *
     * @return an iterator .
     */
    @Override//permite recorrer las tuplas de la pgina
    public Iterator<Tupla> iterator() 
    {
        return new PaginaRanuras.IteradorDePagina();
    }

    /**
     * Clase interna que implementa un iterator de tupla
     * DIGA 18 de Junio - 022600
     */
    private class IteradorDePagina implements Iterator<Tupla> 
    {
        /** El actual indice del iterator. */
        private int indiceActual;

        /**
         * Constructor de un nuevo iterator para el contenido de la página.
         */
        public IteradorDePagina() 
        {
            indiceActual = 0;
        }

        /**
         * Verificar si hay mas tuplas en la página.
         *
         * @return <code>true</code> si hay mas tuplas
         * en la página, <code>false</code> en caso contrario.
         */
        @Override
        public boolean hasNext() 
        {
            return indiceActual < Tuplas.size();
        }

        /**
         * Devuelve la siguiente tupla del iterator.
         *
         * @return la siguiente tupla del iterator.
         */
        @Override
        public Tupla next() 
        {
            return Tuplas.get(indiceActual++);
        }

        /**
         * Elimina la última tupla devuelta por el iterador.
         */
        @Override
        public void remove() 
        {
            int size = GestorIOTupla.byteSize(getRelacion(), Tuplas.get(indiceActual));
            EspacioVacio += size;
            Tuplas.remove(indiceActual);
        }
    }

    /**
     * Devolver un representación textual de la página.
     * 
     * @return representación textual de la página.
     */
    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append("pagina: ").append(getIdentificadorPagina()).append(", tuplas: {\n");
        int tid = 0;
        for (Tupla it : this) {
            sb.append("\t").append(tid++).append(": ").append(it.toString()).append("\n");
        }
        sb.append("}");
        return sb.toString();
    }
}



